/**
 * Created by JetBrains WebStorm.
 * User: hshober
 * Date: 11/10/11
 * Time: 1:43 PM
 * To change this template use File | Settings | File Templates.
 */
var xforms = xforms || {
    classname:"xforms",
    init: function(){
        xforms.models = {};
        xforms.templates = {};
        xforms.indexes = {};
        xforms.variables = {};
        xforms.processId = null;
        xforms.taskId = null;
    },
    clear: function(){
        xforms.removePages();
        xforms.removeScripts();
        xforms.init();
    },
    removePages: function (){
        $("div").not("#loading").each(function(){
            $(this).remove();
        });
    },
    removeScripts: function (){
        $("script[data-role='model']").each(function(){
            $(this).remove();
        });
    },
    findInstance: function(instanceId){
        var instance = null;
        var model;
        for (model in this.models) {
            instance = this.models[model].instances[instanceId];
            if (instance!=null) break;
        }
        return instance;
    },
    findModel: function(modelId){
    	return this.models[modelId];
    },
    defaultContext: {
        model: null
    }
};
xforms.init();

var namespaceResolver = namespaceResolver || {
	_ns: null,

	resolver: function(prefix) {
		return namespaceResolver._ns[prefix] || null;
	},

	init: function() {
		var nsmap = {};
		var attrs = document.firstChild.attributes;
		for ( var i = 0; i < attrs.length; i++ ) {
			var attr = attrs[i];
			if ( attr.name.indexOf('xmlns:') == 0 ) {
				var prefix = attr.name.substring('xmlns:'.length);
				var uri = attr.value;
				nsmap[prefix] = uri;
			}
		}
		namespaceResolver._ns = nsmap;
	}
}
namespaceResolver.init();

var xpathEval = xpathEval || function(xpath, contextNode) {
	function getNodeOrText(node) {
		if ( node.nodeType == Node.TEXT_NODE ) {
			return node.textContent;
		}
		else {
			return node;
		}
	}

	function getNodes(iterator) {
		var node = null, nodes = [];
		while ( null != (node=iterator.iterateNext()) ) {
			nodes.push(getNodeOrText(node));
		}
		return nodes;
	}

	var doc = contextNode.ownerDocument || document;
	var xpResult = doc.evaluate(xpath, contextNode, namespaceResolver.resolver, XPathResult.ANY_TYPE, null);

	if ( !xpResult ) return null;
	else if ( xpResult.resultType == XPathResult.ORDERED_NODE_ITERATOR_TYPE ) return getNodes(xpResult) ;
	else if ( xpResult.resultType == XPathResult.UNORDERED_NODE_ITERATOR_TYPE ) return getNodes(xpResult) ;
	else if ( xpResult.resultType == XPathResult.NUMBER_TYPE ) return xpResult.numberValue ;
	else if ( xpResult.resultType == XPathResult.STRING_TYPE ) return xpResult.stringValue ;
	else if ( xpResult.resultType == XPathResult.BOOLEAN_TYPE ) return xpResult.booleanValue ;
	else if ( xpResult.resultType == XPathResult.ANY_UNORDERED_NODE_TYPE ) return getNodeOrText(xpResult.singleNodeValue) ;
	else if ( xpResult.resultType == XPathResult.FIRST_ORDERED_NODE_TYPE ) return getNodeOrText(xpResult.singleNodeValue) ;

	return null;
};

// jquery plugins
// data selector
(function($){
    var _dataFn = $.fn.data;
    $.fn.data = function(key, val){
        if (typeof val !== 'undefined'){
            $.expr.attrHandle[key] = function(elem){
                return $(elem).attr(key) || $(elem).data(key);
            };
        }
        return _dataFn.apply(this, arguments);
    };
})(jQuery);
// XML serializer
$.fn.serializeXML = function () {
    var out = '';
    if (typeof XMLSerializer != 'undefined') {
        var xs = new XMLSerializer();
        this.each(function() {        	
        	try{
        		out += xs.serializeToString(this);	
        	}catch(e){
        		out += this.xml;
        	}
        });
    } else if (this[0] && this[0].xml != 'undefined') {
        this.each(function() {
            out += this.xml;
        });
    }
    return out;
};
var __next_objid=1;
var objProxyMap = {};
function objectId(obj) {
    if (obj==null) return null;
    
    if (obj.attr("__obj_id")==null) obj.attr("__obj_id",__next_objid++);
    return obj.attr("__obj_id");
}
$.fn.eventProxy = function () {	
	//if ($.browser.msie) {  
		if(objProxyMap[this.attr("__obj_id")]){
			return $(objProxyMap[this.attr("__obj_id")]);
		}else{
			var __obj_id = objectId(this);
			objProxyMap[__obj_id] = {};
			return $(objProxyMap[__obj_id]); 
		}
    /*}else{
    	return this;
    }*/
}
$.fn.xpath = function (path, value) {
    var xpath = path;
    var model;
    var record=null;
    var context = this.context || this[0];
    var attribute;

    //Split out instance id from the path
    var instanceId;
    var re = new RegExp(/instance\(['"](.*)['"]\)(.*)/gi);
    var parts = re.exec(path);
    if (parts != null) {
        var instanceId = parts[1];
        path = parts[2];
    }
    try {
   // Set context if [this] is a model or instance
	if (context.classname=="model") {
        model = context;
        if (instanceId==null) instanceId = context.defaultInstance.id;
        var instance = context.instances[instanceId] || xforms.findInstance(instanceId);
        context = instance.content;
    } else if (context.classname=="instance"){
        model = context.model;
        if (instanceId==null || instanceId==context.id){
            context = context.content;
        } else {
            var instance = context.model.instances[instanceId] || xforms.findInstance(instanceId);
            context = instance.content;
        }
    } else if (instanceId != null) {
        var instance = xforms.findInstance(instanceId);
        context = instance.content;
    } else {
        context = this;
    }

    var iexpath = path;
    // Split out the attribute if identified
    var fieldsPattern = new RegExp(/^(.*)(\.|@[a-zA-Z0-9\-_:]*)$/gi);
    parts = fieldsPattern.exec(path);
    if (parts != null) {
        path = parts[1];
        attribute = parts[2];
    }

    // Convert the xpath to css selector
    if(path!=null && path!=""){
        path = path.replace(/\/$/g, "");
        //path = path.replace(/^(\/\/)/g, "");
        //path = path.replace(/^\//g, "");
        path = path.replace(/\/\//g, " ");
        path = path.replace(/\//g, " > ");
        path = path.replace(/:/g, "|");
        path = path.replace(/@/g, "");
        if(path.indexOf(" ")!=0) path = " > " + path;

    	if(context.context.documentElement!=undefined){//ie error - Unable to get value of the property 'documentElement': object is null or undefined
    		context = $(context.context.documentElement);
    	}
		record = context.find(path);
        if(record.length == 0 ){
        	var root = context[0].nodeName.replace(":","|");
        	var rootPath = " > " + root;

        	if(path.indexOf(rootPath) == 0 ){
        		var pathFromRoot = path.substr(rootPath.length);
        		if(pathFromRoot !=""){
        			if($.browser.msie){
        				record = context.filter(root).find(pathFromRoot);
        				if(record.length == 0){
        					record = context.find(root).find(pathFromRoot);	
        				}
        				if(record.length == 0){
	    					var ns = "xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#' xmlns:saxon='http://saxon.sf.net/' xmlns:dcam='http://purl.org/dc/dcam/' xmlns:vs='http://www.w3.org/2003/06/sw-vocab-status/ns#' xmlns:rdfs='http://www.w3.org/2000/01/rdf-schema#' xmlns:wot='http://xmlns.com/wot/0.1/' xmlns:time='http://www.w3.org/2006/time#' xmlns:swrl='http://www.w3.org/2003/11/swrl#' xmlns:chem='http://rjlg.com/labspaces/chem#' xmlns:rss='http://purl.org/rss/1.0/' xmlns:lsc='http://rjlg.com/labspaces/core#' xmlns:sy='http://purl.org/rss/1.0/modules/syndication/' xmlns:xf='http://www.w3.org/2002/xforms' xmlns:dcelem='http://purl.org/dc/elements/1.1/' xmlns:lims='http://rjlg.com/labspaces/lims#' xmlns:dc='http://purl.org/dc/terms/' xmlns:db='http://docbook.org/ns/docbook' xmlns:ev='http://www.w3.org/2001/xml-events' xmlns:foaf='http://xmlns.com/foaf/0.1/' xmlns:lexinfo='http://www.lexinfo.net/2.0/lexinfo.owl#' xmlns:xsp='http://www.owl-ontologies.com/2005/08/07/xsp.owl#' xmlns:dcmitype='http://purl.org/dc/dcmitype/' xmlns:enum='https://dev.themis.rjlg.com/brianzemba/swift/services/Enumeration/' xmlns:mx='http://www.rjlg.com/XmlMashup' xmlns:vcard='http://www.w3.org/2006/vcard/ns#' xmlns:content='http://purl.org/rss/1.0/modules/content/' xmlns:unit='http://rjlg.com/labspaces/unit#' xmlns:xsd='http://www.w3.org/2001/XMLSchema#' xmlns:swrlb='http://www.w3.org/2003/11/swrlb#' xmlns:owl='http://www.w3.org/2002/07/owl#' xmlns:lsme='http://rjlg.com/labspaces/medicalexaminer#' xmlns:uc='http://ucore.gov/ucore/2.0/codespace#' xmlns:skos='http://www.w3.org/2004/02/skos/core#' xmlns:swift='java:org.swift.mashup.xslt.Extension' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns:lemon='http://www.monnet-project.eu/lemon#'";
	    					try{
	    						context[0].setProperty("SelectionNamespaces", ns);
	    					}catch (e) {
	    						context[0].ownerDocument.setProperty("SelectionNamespaces", ns);
	    					}		
	    					if(iexpath.indexOf("$=")!=-1){//xpath has ends-with selector in it cnverted to contains since xpath 1.0 doesnt support ends-with fn, need to use substring to implement this right
	    						var indexOfEndsWith = iexpath.indexOf("$=")
	    						var beforeEndsWith =  iexpath.substr(0,indexOfEndsWith);
	    						var afterEndsWith =  iexpath.substr(indexOfEndsWith, iexpath.length);
	    						if(beforeEndsWith.lastIndexOf("[")!=-1){
	    							var param1 = iexpath.substr(beforeEndsWith.lastIndexOf("[")+1,iexpath.indexOf("$=") - beforeEndsWith.lastIndexOf("[")- 1);
	    							var param2 = afterEndsWith.substr(2,afterEndsWith.lastIndexOf("'")-1);
	    							var iexpath = iexpath.substr(0,beforeEndsWith.lastIndexOf("[")+1)+ "contains(" + param1 + "," + param2 + ")" + afterEndsWith.substr(afterEndsWith.indexOf("]"));
	    						}else{
	    							
	    						}
	    						
	    					}
	    					var objNodeList = context[0].selectNodes(iexpath);
	    					var nodes = $([]);
	    					for (var i=0; i<objNodeList.length; i++) {
	    						nodes = nodes.add(objNodeList.nextNode());	    					      
	    					}
	    			        nodes = applyXMLTextToNode(nodes);
	    					return nodes;
        				}
        			}else{
        				record = context.filter(root).find(pathFromRoot);            				
        			}
        			path = pathFromRoot;
        		}else{
        			path = path.substr(3);
        			if($.browser.msie){
        				record = context.filter(path);
        				if(record.length == 0){
        					record = context.find(path);	
        				}
        			}else{
        				record = context.filter(path);           				
        			}
        		}
        	}
    	}
    } else {
        record = context;
    }

    //Fetch or set the attribute value if attribute specified
    if(record!=null){
        if(attribute!=null){
            var attr = {
                classname: "attribute",
                name: attribute,
                path: path,
                record: record,
                xmlText: function(value){
                    if (value==null) {
                        if (this.name=="."){
                            return this.record.text();
                        } else if (attribute.substr(0,1)=="@") {
                        	if(this.record.length>1){
                        		var attrStr = "";
                        		for(var i=0;i<=this.record.length-1;i++){
                        			attrStr = attrStr + $(this.record[i]).attr(attribute.substr(1));
                        		}
                        		return attrStr;
                        	}else{
                        		return this.record.attr(attribute.substr(1));
                        	}                            
                        }
                    } else {
                        if (this.name!=null && this.name.substr(0,1)=="@") {
                            this.record.attr(this.name.substr(1),value);
                        } else {
                            this.record.text(value);
                        }
                        var event = jQuery.Event("xforms-value-changed");
                        event.record = this.record;
                        event.value = value;
                        $(this.record).eventProxy().trigger(event);
                    }
                },
                bind: function(event, func){
                    this.record.eventProxy().bind(event,func);
                },
                trigger: function(event){
                    this.record.eventProxy().trigger(event);
                }
            }
            record = attr;
        } else {
            if (record) {
                applyXMLTextToNode(record);
            }

        }
    }
    } catch (e) {
        if (model==null) model = xforms.defaultContext.model;
        var event = jQuery.Event("xforms-binding-exception");
        event.xpath = xpath;
        $(model).trigger(event);
        return null;
    }
   /* if($.browser.msie && record.classname != "attribute"){
    	try{
    		if($(record).length > 0){
    			var recXmlTextFunc = record.xmlText;
        		record = $.xml($(record).serializeXML());
        		record.xmlText = recXmlTextFunc;	
    		}
    	}catch(e){
    		// nothing needs done to the record if the serializeXML fails
    	}
    }*/
    return record;
};
function applyXMLTextToNode(node){
    var $node = node;
    if ($node.context==null) {
        $node = $(node);
    }
    $node.xmlText = function(value){
        if (value==null) {
            return this.text();
        } else {
            this.text(value);
            var event = jQuery.Event("xforms-value-changed");
            event.record = this;
            event.value = value;
            $(this).eventProxy().trigger(event);
        }
    }
    return $node;
}
jQuery.extend(jQuery.expr[':'], {
    nodeset: function (e, index, match, array) {
    if ($(array[index]).data("nodeset")==null) return false;
    for (var i = index -1; i >= 0; i--) {
      if ($(array[i]).data("nodeset")!=null || $(array[i]).data("ref")!=null) {
        var parents = $(e).parents();
        for (var j = parents.length-1; j >= 0; j--){
            if (array[i] == parents[j]) return false;
        }
      }
    }
    return true;
    },
    dataContainer: function (e, index, match, array) {
    var ref = $(e).data("nodeset") || $(e).data("ref");
    if (ref==null) return false;
    var tags = {"div":true,"fieldset":true,"span":true};
    if ($(e).data("nodeset")==null && tags[e.localName]!=true) return false;
    for (var i = index -1; i >= 0; i--) {
      if ($(array[i]).data("nodeset")!=null || $(array[i]).data("ref")!=null) {
        var parents = $(e).parents();
        for (var j = parents.length-1; j >= 0; j--){
            if (array[i] == parents[j]) return false;
        }
      }
    }
    return true;
    },
    ref: function (e, index, match, array) {
      if ($(array[index]).data("ref")==null) return false;
      for (var i = index -1; i >= 0; i--) {
        if ($(array[i]).data("nodeset")!=null || $(array[i]).data("ref")!=null) {
          var parents = $(e).parents();
          for (var j = parents.length-1; j >= 0; j--){
              if (array[i] == parents[j]) return false;
          }
        }
      }
      return true;
    }
});

$(document).ready(function(){
	if(location.pathname.indexOf("/swift/services/Workflow") ==-1){
        xforms.taskId = getURLParameter("taskId");
    	xforms.processId = getURLParameter("process");
    	if ( xforms.processId == 'null' ) {
    	    xforms.processId = getURLParameter("processId");
    	}
    }else{
    	var restParams = location.pathname.split("/");
    	var idxProcess, idxTask;
    	// the index of process and task can vary locally vs VM
    	for ( var i = 0; i < restParams.length; i++ ) {
			if ( restParams[i] == 'Workflow' ) {
				idxProcess = i+1;
				idxTask = i+2;
				break;
			}
    	}
    	try {
	        xforms.processId = restParams[idxProcess] || location.href;
	        xforms.taskId = restParams[idxTask] || location.href;
    	} catch(e){}
    }
	loadXForms(document);
	registerUnifiedListAnimations();
});

function registerUnifiedListAnimations() {
	var fudge = 10;
	$(".unified-list-left .ui-li-link-alt").live("click", function() {
		var item = $(this);
		var li = item.parent('li');
		var w = fudge+li.width();
		li.animate({
			marginLeft: ''+w+'px',
			marginRight: '-'+w+'px',
			opacity: '0%'
		}, 500, 'swing', function() {
			item.trigger('select');
		} );
	} );
	$(".unified-list-right .ui-li-link-alt").live("click", function() {
		var item = $(this);
		var li = item.parent('li');
		var w = fudge+li.width();
		li.animate({
			marginLeft: '-'+w+'px',
			marginRight: ''+w+'px',
			opacity: '0%'
		}, 500, 'swing', function() {
			item.trigger('select');
		} );
	} );
}

function getURLParameter(name) {
    return decodeURIComponent(
        (location.search.match(RegExp("[?&]"+name+"=([^&]*)"))||[,null])[1]
    );  
}


function loadXForms(root){
  // Load Models
    $(xforms).bind("xforms-model-construct-done", function(){
        if (xforms.unprocessedModels <= 0) {
            $(document).find("[data-role='page']").each(function(){
                bindNodesetsAndSingleNodes(xforms.defaultContext, this);
                bindSuggest(this);
            });
            $.each(xforms.models,function(model){
                $(model).trigger("xforms-ready");
            })
            var event = jQuery.Event("xforms-ready");
            $(root).trigger(event);
            
        	bindPageShowEvents();
            bindDateTimeInputs();
		    writeSentinelDiv();
            //Set focus to the first input on the page
            focusFirstElement(document);
        }
    });
	loadModels(root);
}

function writeSentinelDiv(){
    $('<div id="xforms-ready" style="visibility: hidden; display: none;"></div>').appendTo('body');
}

function focusFirstElement(target){
	if($(target).find('.content-primary').length != 0){
		$(target).find('.content-primary :input:enabled:visible:not([readonly="true"]):not([data-type="search"]):first').focus();
    }else{
    	$(target).find('.ui-content :input:enabled:visible:not([readonly="true"]):not([data-type="search"]):first').focus();
    }

}

function bindDateTimeInputs(){
	$(".date, .dateTime").live("change", function() {
		if (!/Invalid|NaN/.test(new XDate($(this).val().replace(/-/g, '/')))) {
			var dateObj = new XDate($(this).val().replace(/-/g, '/'));
			var hiddenInputId = "#" + $(this).attr("for");
			$(hiddenInputId).val(dateObj.getTime());
			$(hiddenInputId).trigger("change");
		}
	});
	$(".hidden-date").live("change", function() {
		if (!/Invalid|NaN/.test(new XDate(parseInt($(this).val())))) {
			var dateObj = new XDate(parseInt($(this).val().replace(/-/g, '/')));
			var inputId = "#" + $(this).attr("for");
			var format = null;
			if($(inputId).hasClass("dateTime")){
				format = "dd MMM yyyy HH:mm:ss";
			}else{
				format = "dd MMM yyyy";
			}
			$(inputId).val(dateObj.toString(format));
		}
	});
}

function bindPageShowEvents(){
	$('body').live('pagebeforeshow',function(page, options){
		// reset filters for the page
		$(page.target).find("[data-type='search']").each(function(){
			$(this).val('');
			$(this).trigger("change");
		});
		// reset validation for the form
		$(page.target).find("form").each(function(){
			var task = {target:this};
			resetValidation(this,task,null);
		})
	});
	$('body').live('pageshow',function(page, options){
		focusFirstElement(page.target);
	});
	$('div[data-role="page"]').bind("pageshow",refreshSuggests);
}

function getDocumentNamespaces() {
	var nstext = "";
    if ( document.namespaces ) {
		for ( var i = 0; i < document.namespaces.length; i++ ) {
			nstext += 'xmlns:' + document.namespaces[i].name + '="' + document.namespaces[i].urn + '" ';
		}
    }
    else {
	    $(document).find("html").first().each(function(index){
	        $.each(this.attributes, function(i, attrib){
	            var name = attrib.name;
	            if (name.indexOf("xmlns")==0) {
	                nstext += name + '="' + attrib.value + '" ';
	            }
	        });
	    });
    }

    return nstext;
}

function loadModels(xml){
    $.xmlns["xf"] = "http://www.w3.org/2002/xforms";
    var root = xml || document;
    var nstext = getDocumentNamespaces();

    xforms.unprocessedModels = 0;
    var modelGUID = 0;
    $(root).find("script[data-role='model']").each(function(index){
        var xml = $(this).html();
        if ( (nstext != null && xml.indexOf("xmlns:")==-1) || (nstext != null && xml.indexOf("xmlns=")==-1) ) {
            xml = xml.replace(/<([^>]+)>/, '<\$1 '+nstext+'>');
        }
        xml = $.parseXML(xml);
        var modelCount = $(xml).find("xf|model").length;
        xforms.unprocessedModels = xforms.unprocessedModels + modelCount;
        $(xml).find("xf|model").each(function(){
            var model = {
                classname: "model",
                instances:{},
                submissions:{},
                variables:{},
                xml: this,
                find: function(path){
                    var nodeset;
                    nodeset = $(this).xpath(path);
                    return nodeset;
                },
                setValue: function(path, value){
                    var nodeset;
                    nodeset = $(this).xpath(path).xmlText(value);
                    return nodeset;
                },
                getInstance: function (path) {
                    var model = this;
                    var instance = null;
                    var re = new RegExp(/instance\(['"](.*)['"]\)(.*)/gi);
                    var parts = re.exec(path);
                    if (parts != null) {
                        instance = model.instances[parts[1]];
                    } 
                    if (instance==null) {
                    	instance = model.instances[path];
                    }
                   return instance;
                }
            };
            model.id = $(this).attr("id") || 'model_' + modelGUID++;
            xforms.models[model.id] = model;
            model.unprocessedInstances = 0;
            
            if (xforms.defaultContext.model == null) {
                xforms.defaultContext.model = model;
            }
            var attributes = this.attributes; // returns an array of attributes?
            $.each(attributes, function (i, attribute) {
                if (attribute.prefix=="xmlns"){
                    var uri = attribute.value;
                    var prefix = attribute.localName;
                    $.xmlns[prefix] = uri;
                }
            })
            var instanceCount = 0;
            $(this).find("xf|instance").each(function(){
                var url = $(this).attr("src") || $(this).attr("resource");
                var id = $(this).attr("id") || 'instance_' + instanceCount++;
                var instance = {
                    classname: "instance",
                    id: id,
                    url: url,
                    method: "GET",
                    type: "xml",
                    model: model,
                    find: function(path){
                        var nodeset;
                        nodeset = $(this).xpath(path);
                        return nodeset;
                    },
                    setValue: function(path, value){
                        var nodeset;
                        nodeset = $(this).xpath(path).xmlText(value);
                        return nodeset;
                    }
                };
	            model.unprocessedInstances += 1;
                if (this.childElementCount > 0){
                	if ($.browser.msie){
                		var xml = new ActiveXObject( "Microsoft.XMLDOM" );
            			xml.async = "false";
            			xml.loadXML( $(this.firstElementChild).serializeXML() );
            			instance.content = xml.firstChild;
                		//instance.content = this.firstElementChild;	
                	}else{
                		instance.content = this.firstElementChild;	
                	}                
                } else content = null;
                model.instances[instance.id] = instance;
                if (model.defaultInstance==null) {
                    model.defaultInstance=instance;
                }
            })
            $(this).find("xf|submission").each(function(){
                var submission = {};
                submission.id = $(this).attr("id") || 'default';
                submission.ref = $(this).attr("ref");
                submission.queryString = null;
                submission.instance = $(this).attr("instance");
                submission.method = $(this).attr("method");
                submission.action = $(this).attr("action") || $(this).attr("resource");
            	submission.actionRef = $(this).find("resource").attr("value");
                submission.async = ($(this).attr("mode")=="synchronous") ? false : true;
                submission.replace = $(this).attr("replace");
                submission.xml = this;
                submission.model = model;
                model.submissions[submission.id] = submission;
                bindActions(model, submission);
                $(submission).bind("xforms-submit", function(event){
                   onSubmit(this, event);
                });
            })
            $(model).bind("xforms-model-construct-done", function(){
                --xforms.unprocessedModels;
                var event = jQuery.Event("xforms-model-construct-done");
                $(xforms).trigger(event);
            });
            $(model).bind("xforms-instance-construct-done xforms-instance-construct-error", function(){
                model.unprocessedInstances -= 1;
                if ( model.unprocessedInstances <= 0 ) {
                    var event = jQuery.Event("xforms-model-construct-done");
                    $(model).trigger(event);
                }
            }); 
            $(model).bind("xforms-model-construct", function(){
                bindActions(model, model);
                loadModelData(model);
            });
        })
    })
    $.each(xforms.models, function(key, model){
        var event = jQuery.Event("xforms-model-construct");
        $(model).trigger(event);
    });
}
function loadModelData(model){
    // Load Namespaces
    $(model.namespaces).each( function(index){
        $.xmlns[this.prefix] = this.URI;
    });
    // Load Instances
    if($.isEmptyObject(model.instances)){
        var event = jQuery.Event("xforms-instance-construct-done");
        $(model).trigger(event);
    }  
    $.each(model.instances, function(key, instance){
        if (instance.url!=null){
            $.ajax( {
            	headers: {
            		XThemisProcess: xforms.processId,
            		XThemisTask: xforms.taskId,
            		XThemisForm: location.href
        		},
                context: instance,
                async: true,
                type: instance.method,
                url: cacheKiller(instance.url),
                dataType: instance.type,
                success: function(response) {
                    processInstanceXml(response, instance);
                    var event = jQuery.Event("xforms-instance-construct-done");
                    event.instance = instance;
                    $(model).trigger(event);
                },
                error: function(response) {
                    var event = jQuery.Event("xforms-instance-construct-error");
                    event.instance = instance;
                    $(model).trigger(event);
                }
            });
        } else {
            loadStaticInstance(instance);
            var event = jQuery.Event("xforms-instance-construct-done");
            event.model = model;
            $(model).trigger(event);
        }
    });
}
//Now that that's out of the way, we can start parsing the XML. As you can see, when the request succeeds, the function parseXML is called. That's where I'm going to put my code. Let's start by finding the author of each tutorial, which are stored as attributes on the Tutorial tag.
function processInstanceXml(xml, instance){
	instance = instance || this;
    var $data = $(xml)
    instance.content = $data;
    $(instance).trigger("xforms-refresh");
}
function loadStaticInstance(instance){
    //var xml = $.parseXML(model.content);
    var xml = instance.content;
    var $data = $(xml)
    instance.content = $data;
    $(instance).trigger("xforms-refresh");
}
function resetValue(el){
    var context = $(el).data("context");
    // Set the value
    if (context != null && context.ref != null){
        var value = context.ref.xmlText();
        var expression = $(el).data("value");
        if (expression!=null) {
            expression = "var ref='"+value+"';" + expression;
            value = eval(expression);
            // we need to decode entities, so set the html on some element and call text()
            value = $('<div/>').html(value).text();
        }
        switch (el.localName) {
            case "a":
            case "li":
            case "button":
                $(el).data("ref-value", value);
                break;
            case "legend":
            case "label":
            case "output":
                $(el).text(value);
                break;
            case "span":
                $(el).text(value);
                break;
            case "img":
                $(el).attr("src", value);
                break;  
            case "input":
                $(el).val(value);
            	if($(el).hasClass("hidden-date")){ 
            		if (!/Invalid|NaN/.test(new XDate(parseInt($(el).val())))) {
            			var dateObj = new XDate(parseInt($(el).val().replace(/-/g, '/')));
            			var input = $(el.parentElement).find("#" + $(el).attr("for"));
            			var format = null;
            			if($(input).hasClass("dateTime")){
            				format = "dd MMM yyyy HH:mm:ss";
            			}else{
            				format = "dd MMM yyyy";
            			}
            			$(input).val(dateObj.toString(format));
            		}
            	}
                break; 
            case "ul":
            	if($(el).hasClass("xformSuggest")){ 
            		var inputli = $(el).find(".xformSuggest-inputli");
            		if($(el).attr("data-multiSelect")=="false"){
            			if($(el).find(".xformSuggest-bit").length > 1){
            				break;
            			}else{
                			$(inputli).css("display","block");
            			}
            		}
            		var remainingWidth = 0;
            		$(inputli).css("width","150px");
            		$(el).find(".xformSuggest-bit").remove();
            		$(context.ref).children().each(function(index,child){
            			var textElement = $("<a href='#' class='xformSuggest-bit-text'>" + $(this).xpath($(el).data().displaylabel).xmlText() + "</a>");
                    	var deleteElement = $("<a href='#' class='xformSuggest-bit-box-deletebutton'> </a>");
                    	var liElement = $("<li class='xformSuggest-bit xformSuggest-bit-box xformSuggest-bit-box-deletable' style='float:left; padding-right:5;'> </li>");
                    	liElement.append(textElement);
                    	liElement.append(deleteElement);
                    	$(liElement).data("ref",$(el).data("ref")+"/"+this.nodeName);
                    	$(liElement).data("context",$(el).data("context"));
                    	$(liElement).data("context").repeatKey = this.nodeName;
                    	$(liElement).data("index",index);
                    	inputli.before(liElement);
                    	$(deleteElement).bind("click",function(){
                    		var context = $(this.parentNode).data("context");
                    		var item2delete = $(context).xpath($(this.parentNode).data("ref")).eq($(this.parentNode).data("index"));
                    		item2delete.remove();
                    		var ev = jQuery.Event("xforms-value-changed");
                    		ev.context = context;
                    		$(context.ref).eventProxy().trigger(ev);
                    		if($(el).attr("data-multiSelect")=="false"){
                    			$(inputli).css("display","block");
                    		}
                    	}); 
                    	$(liElement).bind("click",function(){
                    		var context = $(this).data("context");
                    		var itemClicked = $(context).xpath($(this).data("ref")).eq($(this).data("index"));
                    		context.model.variables["$"+$(el).attr("id")+"_node"] = itemClicked;
                    		context.model.variables["$"+$(el).attr("id")+"_index"] = $(this).data("index");
                    		var ev = jQuery.Event("xforms-select");
                    		$(el).trigger(ev);
                    	}); 
                    	/*if($(el).find("li.xformSuggest-bit:last").length!=0){
                    		$(el).find("li.xformSuggest-bit:last").after(liElement);
                    	}else{
                    		$(el).prepend(liElement);
                    	}*/
                    	if($(el).attr("data-multiSelect")=="false" && $(el).find(".xformSuggest-bit").length >= 1){
                			$(inputli).css("display","none");
                		}
            		});
            		remainingWidth = $(el).width() - (inputli.offset().left - $(el).offset().left);
            		$(inputli).css("width",remainingWidth + "px");
            	}
            	break;  
            case 'textarea' :
            	$(el).val(value);
            	//autoTextAreaSize(el);
            	break;
            default:
                $(el).val(value);
        }
    }
    if (context != null && context.label != null){
        var value = context.label.xmlText();
        // we need to decode entities, so set the html on some element and call text()
        value = $('<div/>').html(value).text();
        $(el).text(value);
    }
    if (el.type == 'radio' || el.type == 'checkbox'){
        var checked = false;
        if (context!=null && context.copy != null){
            var copyTo = getControlGroupContext(context).ref;
            var origin = context.copy;
            var node = findNodeInSet($(copyTo).children(), origin);
            checked = (node!=null);
        } else if (context!=null && context.ref != null){
            var target = getControlGroupContext(context).ref.xmlText();
            var origin = context.ref.xmlText();
            checked = (target == origin);
        } else if (context!=null) {
            var target = getControlGroupContext(context).ref.xmlText();
            var origin = $(el).val();
            checked = (target == origin);
        } else {
            checked = el.checked;
        }
        if (checked) {
            $(el).attr('checked',true);
            //el.checked = true;
        } else {
            $(el).attr('checked',false);
            //el.checked = false;
        }
        try {
            $(el).checkboxradio("refresh");
        } catch (e){
          // Do nothing
        }
    }
    if (el.localName=="select"){
        try {
            $(el).selectmenu("refresh", true);
        } catch (e){
          // Do nothing
        }
    }
}
function findNodeInSet(nodeset, node){
    var foundNode;
    var xml = $(node).serializeXML();
    $(nodeset).each(function(){
        var item = this;
        if ($(item).serializeXML() == xml ) {
            foundNode = item;
            return;
        }
    });
    return foundNode;
}
function refreshNodeset(element, parentContext, template){
    var context = resolveContext(element, parentContext, "nodeset");
    if (context == null) return;
    var nodeset = context["nodeset"];
    $(element).empty();
    if(nodeset == null) return context;
    var index = 1;   
    nodeset.each(function(){
        var el = $(template).clone(true);
        var repeatingcontext = {
            "model": context.model,
            "instance": context.instance,
            "parent": context,
            "index": index,
            "repeatKey": element.id,
            "ref": applyXMLTextToNode(this)
        };
        bindNodesetsAndSingleNodes(repeatingcontext, el);
        if (index > 1){
            el.find("[id],[for]").each(function(){
                var child = this;
                var id = $(child).attr("id");
                if (id!=null) {
                    $(child).attr("id", id + "-" + index);
                }
                var fid = $(child).attr("for");
                if (fid!=null) {
                    if (fid!=null) $(child).attr("for", fid + "-" + index);
                }
            });
        }
        /*
        el.children().each(function(){
            var child = this;
            $(element).append(child);
        });
        */
        el.children().each(function(){
            var child = this;
            var repeat = $(child).data("repeat");
            if (repeat!="none" || index==1){
                $(element).append(child);
                if(index % 2 == 0) $(child).addClass("row-b");
            }
        });
        if (!context.repeat) return false;
        index++;
    })
    //}
    applyStyleToGroup(element);
    return context;
}
function applyStyleToGroup(element){
    $(element).find("[data-target-role]").each(function(){
        var targetRole = $(this).attr("data-target-role");
        if (targetRole) $(this).attr("data-role", targetRole);
        $(this).removeAttr("data-target-role");
    });
    $(element).find("[data-role='none']").each(function(){
    	if($(this).hasClass('neverstyle') != 'true'){
    		$(this).removeAttr("data-role");
    	}
    });
    $(element).find("[data-role]").each(function(){
        var role = $(this).attr("data-role");
        switch (role){
            case "fieldcontain":
                var groups = $(this).find("[type='radio'],[type='checkbox']");
                if (groups.length > 0) repaintElement(this);
                break;
            case "controlgroup":
            case "page":
            case "model":
            case "main":
            case "content":
            case "group":
            case "header":
            case "footer":
            case "collapsible":
            case "button":
            case "listview":
            case "none":
            default:
                //do nothing
        }
    });
    if($(element).attr("forcedRepaint") == "true"){
    	forcedRepaint(element);
    }
    switch (element.localName){
        case "select":
            repaintSelect(element);
            break;
        default:
    }
}
function repaintElement(el){
	var neverstyle = $(el).find(".neverstyle");
	if(neverstyle.length > 0)return;
    if ($(el).data("styled")) return;
    $(el).trigger("create");
    $(el).data("styled",true);
}

function forcedRepaint(el){
	var contentTheme = $(el).parents("[data-content-theme]").attr('data-content-theme');

    //if ($(el).data("styled")) return;       
    $(el).children().each(function(){
    		if(contentTheme){
    			setContentTheme(this,contentTheme)
    		}else{
    			setTheme(this);
    		}
    	});
    $(el).trigger('create');
    try{
    	if($(el).attr('data-role') == "listview"){
    		$(el).listview("refresh");
    	}
    }catch(e){
    	// do nothing
    }
    //$(el).data("styled",true);
}
function setTheme(el){
	$(el).attr('data-theme',this.THEME);
	if($(el).attr('data-content-theme') != null){
		var contentTheme = $(el).attr('data-content-theme');
		$(el).children().each(function(){setContentTheme(this,contentTheme)});
	}else{
		$(el).children().each(function(){setTheme(this)});
	}

}
function setContentTheme(el,theme){
	$(el).attr('data-theme',theme);
	$(el).children().each(function(){setContentTheme(this,theme)});
}

function repaintSelect(el){
	if($(el).hasClass("neverstyle")){
		return;
	}
    if ($(el).data("styled")) {
        $(el).selectmenu("refresh");
    } else {
        if ($(el).attr("data-role")=="none") $(el).removeAttr("data-role")
        $(el).selectmenu();
        $(el).selectmenu("refresh");
    }
    $(el).data("styled",true);
}
function getTemplate(el){
    var id = el.id;
    if (!(id)) {
        var newDate = new Date;
        id = "id_" + newDate.getTime();
        $(el).attr("id", id);
    }
    var template = xforms.templates[id] || $(el).clone(true);
    xforms.templates[id] = template;
    return template;
}

function resolveContext(element, parentContext, contextType){
    var context = $(element).data("context");
    if (context==null) {
        context = {"parent":parentContext,"element":element};
        $(element).data("context", context);
        var modelid = $(element).data("model");
        context.model = xforms.models[modelid] || parentContext.model;
    }
//    if (context[contextType]!=null) return context;
    var model = context.model;
    var xpath = null;
    if (contextType=="nodeset") {
        xpath = $(element).data("nodeset") || $(element).data("ref") ;
        context.repeat = ($(element).data("nodeset")!=null);
    } else {
        xpath = $(element).data(contextType);
    }
    if (xpath==null) return context;
    var explicit = (xpath.indexOf("instance(")==0);
    //Explicit instance references override default location in XML structure
    if(explicit) {
        context.instance = model.getInstance(xpath) || model.defaultInstance;
        context[contextType] = $(model).xpath(xpath) || null;
        context.repeatKey = "none";
        context.index = 1;
    } else {
        context.repeatKey = parentContext.repeatKey;
        context.index = parentContext.index;
        var parentNodeContext;
        parentNodeContext = parentContext.nodeset || parentContext.ref;
        context.instance = parentContext.instance || model.defaultInstance;
        if (parentNodeContext==null){
            parentNodeContext = context.instance.content;
        }
        context[contextType] = $(parentNodeContext).xpath(xpath);
    }
    return context;
}

var outputelements = {output:"output",span:"span",fieldset:"fieldset",option:"option",a:"a",li:"li",button:"button",label:"label",legend:"legend"};

function bindNodesetsAndSingleNodes(parentContext, parent){
    var display = parent || document;
    $(display).find(":dataContainer").each(function(){
        var element = this;
        var bound = $(element).data("bound-nodeset");
        if (bound) return;
        var name = element.localName;
        if ($(element).data("nodeset")==null) {
            var context = refreshSingleNode(element, parentContext);
            $(context.instance).bind("xforms-refresh xforms-insert xforms-delete", function(event){
                context.ref = null;
                refreshSingleNode(element, parentContext);
            });
        } else {
            var template = getTemplate(element);
            var context = refreshNodeset(element, parentContext, template);
            $(context.instance).bind("xforms-refresh xforms-insert xforms-delete", function(event){
                 context.nodeset = null;
                 refreshNodeset(element, parentContext, template);
            });
        }
        $(element).data("bound-nodeset",true);
    });
    $(display).find(":input,output[data-ref],option[data-ref],ul[data-ref],li[data-ref],a[data-ref],button[data-ref],label[data-ref],legend[data-ref],img[data-ref]").each(function(){
        var element = this;
        var context = bindSingleNodesByContext(element, parentContext);
    });

    bindSubmission(display, parentContext);
    applyStyleToGroup(display);
}
function refreshSingleNode(element, parentContext){
    var context = bindSingleNodeContainerContext(element, parentContext);
    if (context !=null ) bindNodesetsAndSingleNodes(context, element);
    return context;
}
function bindSingleNodeContainerContext(element, parentContext){
    //exit if bound;
    var context = resolveContext(element, parentContext, "ref");
    resolveContext(element, parentContext, "label");
    resolveContext(element, parentContext, "copy");
    return context;
}
function bindSingleNodesByContext(element, parentContext){
    //exit if bound;
    var bound = $(element).data("bound");
    if (bound) return;
    var context = resolveContext(element, parentContext, "ref");
    var node = context.ref;
    $(node).eventProxy().bind("xforms-value-changed", function(event){
        resetValue(element);
    });
    resolveContext(element, parentContext, "label");
    var label = context["label"];
    $(label).eventProxy().bind("xforms-value-changed", function(event){
        resetValue(element);
    });
    resolveContext(element, parentContext, "copy");
    var copy = context["copy"];
    $(copy).eventProxy().bind("xforms-value-changed", function(event){
        resetValue(element);
    });
    resetValue(element);
    if (!(outputelements[element.localName])) bindInputElement(element)
    if ($(element).data("bound")==null){
        $(context.instance).bind("xforms-refresh xforms-insert xforms-delete", function(event){
            $(element).data("bound",false);            
        });
    }
    $(element).data("bound",true);
    return context;
}
function bindInputElement(element){
    // Apply value change back to instance
    var type = $(element).attr("type");
    $(element).bind("paste change", function(event){
        setTimeout(function(){
            onValueChange(element);
        }, 0);
    });
    if (type == "radio" || type == "checkbox") {
        var context = $(element).data("context");
        var containerContext;
        var groupContext = getControlGroupContext(context);
        if (groupContext!=null) containerContext = groupContext.ref;
        if (containerContext!=null){
            $(containerContext).eventProxy().bind("xforms-value-changed", function(event){
                resetValue(element);
            });
        }
    }
    var incremental = $(element).data("incremental");
    if (incremental && !$(element).data("incremental-bound")){
        var needsDelay = true;
        var charactersPressed = 0;
        var skip = false;
        $(element).keypress(function(event){
            charactersPressed++;
            if (!skip) {
                skip = true;
                needsDelay = (charactersPressed<=3);
                if(needsDelay) {
                    setTimeout(function(){
                        onValueChange(element);
                        charactersPressed = 0;
                        $(element).trigger("incremental-change");
                        skip = false;
                    }, 1500);
                } else {
                    setTimeout(function(){
                        onValueChange(element);
                        charactersPressed = 0;
                        $(element).trigger("incremental-change");
                        skip = false;
                    }, 0);
                }
            }
        });
        $(element).data("incremental-bound",true);
    }
}
function bindSubmission(display, parentContext){
	$(display).find("button[data-submission],a[data-submission]").each(function(){
        var button = this;
        var subId = $(button).data("submission");
        var isBound = $(button).data("bound-submission");
        if(isBound==true) return;
        var context = resolveContext(button, parentContext, "ref");
        if (context) {
            var model = context.model;
            var submission = model.submissions[subId];
            $(button).click( function(event){
                $(submission).trigger("xforms-submit");
            });
        }
        $(button).data("bound-submission",true);
    });
    $(display).find(":input[data-submission]").each(function(){
        var input = this;
        var subId = $(input).data("submission");
        var isBound = $(input).data("bound-submission");
        if(isBound==true) return;
        var context = resolveContext(input, parentContext, "ref");
        if (context) {
            var model = context.model;
            var submission = model.submissions[subId];
            $(input).change( function(event){
                setTimeout(function(){
                    $(submission).trigger("xforms-submit");
                }, 0);
            });
        }
        $(input).data("bound-submission",true);
    });
}
function getControlGroupContext(context){
    var controlGroupContext=null;
    if (context==null) return;
    var element = context.element;
    if (element!=null) {
        var role = $(element).data("target-role") || $(element).data("role");
        if (role=="controlgroup") {
            controlGroupContext = context;
        } else {
            controlGroupContext = getControlGroupContext(context.parent);
        }
    } else {
        controlGroupContext = getControlGroupContext(context.parent);
    }
    return controlGroupContext;
}
function onValueChange(el){
    var context = $(el).data("context");
    if (el.type == 'radio' || el.type == 'checkbox'){
        if (context != null && context.copy != null){
            var copyTo = getControlGroupContext(context);
            if (copyTo != null){
                var origin = context.copy;
                if (el.checked) {
                    var originClone = $(origin).clone();
                    $(copyTo.ref).append(originClone);
                } else {
                    var node = findNodeInSet($(copyTo.ref).children(), origin);
                    if (node!=null) {
                        $(node).remove();
                    }
                }
                var ev = jQuery.Event("xforms-refresh");
                ev.context = copyTo;
                $(copyTo.instance).trigger(ev);
            }
        } else if (context != null){
            var value = "";
            var target;
            var groupContext = getControlGroupContext(context);
            if (groupContext!=null) {
                target = groupContext.ref;
                if (el.checked) {
                    if(context.ref != null){
                        value = context.ref.xmlText();
                    }else{
                        value = el.value;
                    }
                }
                target.xmlText(value);
            }
        }
    } else {
        var value = el.value;
        if(context.ref != null){
            context.ref.xmlText(value);        
	        var ev = jQuery.Event("xforms-value-changed");
	        ev.context = context;
	        ev.value = value;
	        $(context.instance).eventProxy().trigger(ev);
        }
    }
    if (el.localName=="select"){
        try {
            $(el).selectmenu("refresh",true);
        } catch (e){
          // Do nothing
        }
    }

}

function bindSuggest(display){
    $(display).find("ul[data-role='suggest']").each(function(elemCount){
        
    	var listTemplate = $(this);
        var tagId = "#" + listTemplate.attr("for");
        var input = $.find(tagId + "-input");
        if (input != null){
            var targetModel = listTemplate.data("model") || xforms.defaultContext.model.id;
            var submissionId = listTemplate.data("submission");
            var model = xforms.models[targetModel];
            var suggestTimeout = null;
            var suggestList = null;
            var suggest = $(tagId);
        	var suggestSubmission = $(this).data("context").model.submissions[$(input).data("suggestSubmission")];
            
        	$($(suggest).data("context").instance).bind("xforms-refresh xforms-insert xforms-delete", function(event){
                resetValue(suggest[0] || suggest.context);            
            });
        
            var focus = function(list,direction){            
	    		var currentItem = suggestList.find("li.xformSuggest-autocomplete-result-focus");
	    		if(currentItem.length == 0){
	    			currentItem = suggestList.find("li:first");
    				$(currentItem).addClass("xformSuggest-autocomplete-result-focus");
    				$(currentItem).children().addClass("xformSuggest-autocomplete-result-focus");
	    		}else{
	    			if(direction == 'down'){
	    				if($(currentItem).next().length !=0){
		    				$(currentItem).removeClass("xformSuggest-autocomplete-result-focus");
		    				$(currentItem).children().removeClass("xformSuggest-autocomplete-result-focus");
			    			$(currentItem).next().addClass("xformSuggest-autocomplete-result-focus");
			    			$(currentItem).next().children().addClass("xformSuggest-autocomplete-result-focus");
		    			}
	    			}else{
	    				if($(currentItem).prev().length !=0){
		    				$(currentItem).removeClass("xformSuggest-autocomplete-result-focus");
		    				$(currentItem).children().removeClass("xformSuggest-autocomplete-result-focus");
			    			$(currentItem).prev().addClass("xformSuggest-autocomplete-result-focus");
			    			$(currentItem).prev().children().addClass("xformSuggest-autocomplete-result-focus");
		    			}
	    			}	    			        		    
	    		}
        	};
        
        	var selectSuggestedItem = function(el,suggestId){
     	        var copyToElement = null;
     	        var context = $(el).data("context");
             	if (context != null && context.copy != null){
     	        	var copyTo = null;
     	        	if($(el).hasClass("xformSuggest-autocomplete-result-a")){
     	        		var ulElementId = "#" + $(el).data("controlgroup"); 
     	        		copyToElement = $(ulElementId);
     	        		copyTo = $(copyToElement).data("context");
     	        	}         
     	            if (copyTo != null){
		                var origin = context.copy;		                
		                var originClone = $(origin).clone();
		                //try{
		                	$(copyTo.ref).append(originClone);
		               /* }catch(e){
		                	var newXml = $.xml(copyTo.ref.serializeXML()).append(originClone);
		                	var xmlTextCopy = copyTo.ref.xmlText; 
			                copyTo.ref = $(newXml);
			                copyTo.ref.xmlText = xmlTextCopy; 
		                }		*/                
		                if(suggest.attr("data-multiSelect")=="false"){                    
	    	    			var ev = jQuery.Event("blur");
	    		            $(input).trigger(ev);
        				}
     	                var ev = jQuery.Event("xforms-insert");
     	                ev.context = copyTo;
     	                $(copyTo.instance).trigger(ev);
     	            }
     	        }else{     	        	                    
     	        	if(suggest.attr("data-multiSelect")=="false"){                    
		    			var ev = jQuery.Event("blur");
			            $(input).trigger(ev);
     				}
     	        	model.variables["$"+suggestId+"_value"] = $("#"+suggestId+"-input").val(); 
     	        	var ev = jQuery.Event("xforms-out-of-range");
     	        	$("#"+suggestId).trigger(ev);
 	                
     	        } 
        	};
        	$(suggestSubmission).bind("xforms-submit-done", function(){
        		if(suggest.attr("data-multiSelect")=="false"){
        			if(suggest.find(".xformSuggest-bit").length = 1){
        				return;
        			}
        		}
            	$(suggestList).css("display","block");     
            	var input = "#" + $(suggestList).attr("id").replace("ul-options-","") + "-input";
            	var maxHeight = ($("div.ui-page-active .ui-content").height()-50) - $(input).offset().top + $(".ui-page-active .ui-header").offset().top;
		    	if(maxHeight < 50){    
    		    	var selectedList = $("#" + suggestList.attr("id").replace("ul-options-",""));
            		var margin = "-" + ($(suggestList).height() + $(selectedList).height()+8) + " 0 0 0";
            		$(suggestList).css("margin",margin);
		    	}
            });
            $(input).bind({
            	keyup: function(event){
            		// handle backspace delet arrows enter tab
            		if((90>=event.keyCode && event.keyCode>=48) 
        		        || (105>=event.keyCode && event.keyCode>=96) 
        		        || (event.keyCode == 8) || (event.keyCode == 46) )
        		    {
            			if($(this).val().length > 3){    
	            			if(suggestTimeout){
	            				 clearTimeout(suggestTimeout);
	            			}
	            			var submission = $(this).data("context").model.submissions[$(this).data("suggestSubmission")];
	            			suggestSubmission.queryString = "?searchText=" + this.value;
	                		suggestTimeout = setTimeout(function(){
	    	                    $(suggestSubmission).trigger("xforms-submit");	    	                    
	    	                }, 200);
	            		}
        		    }
            	},
            	focus: function(){
    		    	suggestList = $("ul[for = " + this.id.replace("-input","")+ "]");
    		    	var maxHeight = ($("div.ui-page-active .ui-content").height()-50) - $(this).offset().top + $(".ui-page-active .ui-header").offset().top;
    		    	if(maxHeight < 50){    	     
    		    		var selectedList = $("#" + this.id.replace("-input",""));
    		    		maxHeight = $(selectedList).offset().top;
    		    		$(suggestList).css("max-height",maxHeight-80);
    		    		var margin = "-" + ($(suggestList).height() + suggest.height()+8) + " 0 0 0";
    		    		$(suggestList).css("margin",margin);
        		    	suggest.css("border-radius","0.0em 0.0em 0.6em 0.6em");
    	    			$(suggestList).css("border-radius","0.6em 0.6em 0.0em 0.0em")
    		    	}else{
    		    		$(suggestList).css("max-height",maxHeight);
        		    	suggest.css("border-radius","0.6em 0.6em 0.0em 0.0em");
    	    			$(suggestList).css("border-radius","0.0em 0.0em 0.6em 0.6em")
    		    	};
    		    	$(suggestList).css("display","block");
	    			var suggestOffset = $(suggestList).offset();
	    			var selectedOffset = suggest.offset();
	    			$(suggestList).offset({left:selectedOffset.left, top:suggestOffset.top});
	    			$(suggestList).width(suggest.width()+9);
            	},
            	blur: function(){
    		    	suggestList = $("ul[for = " + this.id.replace("-input","")+ "]");
    		    	setTimeout(function(){
    		    		suggest.css("border-radius","0.6em 0.6em 0.6em 0.6em");
        	    		var itemToUnselect = suggestList.find("li.xformSuggest-autocomplete-result-focus");
	    				$(itemToUnselect).removeClass("xformSuggest-autocomplete-result-focus");
	    				$(itemToUnselect).children().removeClass("xformSuggest-autocomplete-result-focus");
    		    		$(suggestList).css("display","none");
	                }, 200);
            	},
            	keydown: function(event){
            		if((event.keyCode == 38) || (event.keyCode == 40)){
        		    	suggestList = $("ul[for = " + this.id.replace("-input","")+ "]");
        		    	if(event.keyCode == 38){
        		    		focus(suggestList,"up");
        		    	}else{
        		    		focus(suggestList,"down");
        		    	}
            		}else if(event.keyCode == 13 || event.keyCode == 9){
        				suggestList = $("ul[for = " + this.id.replace("-input","")+ "]");
        	    		var selectedItem = suggestList.find("li.xformSuggest-autocomplete-result-focus");
        	    		var anchor = $(selectedItem).find("a");
        	    		if($(this).val()!="" || anchor.length !=0){
            	    		selectSuggestedItem(anchor,this.id.replace("-input",""));
            	    		$(this).val("");            	    		     
            			}
        	    		if(event.keyCode == 13){
            	    		$(this).trigger("blur");
        	    		}
            		}
            	}
            });
        }

        $(this).find(".xformSuggest-autocomplete-result-li").live({        
    		mouseover:function(){            	        	   	        
	        	var currentItem = $(listTemplate).find("li.xformSuggest-autocomplete-result-focus");
				currentItem.removeClass("xformSuggest-autocomplete-result-focus");
				currentItem.children().removeClass("xformSuggest-autocomplete-result-focus");
				$(this).addClass("xformSuggest-autocomplete-result-focus");
				$(this).children().addClass("xformSuggest-autocomplete-result-focus");      
	        },
    		mouseout:function(){     
				$(this).removeClass("xformSuggest-autocomplete-result-focus");
				$(this).children().removeClass("xformSuggest-autocomplete-result-focus");
    		},
    		click:function(){            	        	   
    			selectSuggestedItem($(this).find(".xformSuggest-autocomplete-result-a "),""); 
    			$(input).val("");
    			$(input).focus();
    		}
		});
    });
}

function refreshSuggests(){
    $(this).find("ul.xformSuggest").each(function(){
    	resetValue(this);
    });
    
}

function bindActions(model, target){
    var xml = target.xml;
    $(xml).find("> xf|action,> xf|send,> xf|insert,> xf|delete,> xf|setvalue,> xf|message,> xf|load,> xf|variable,> xf|bind,> xf|confirm").each(function(){
        var action = {
            classname: "action",
            event: $(this).attr("ev:event"),
            expression: $(this).attr("if"),
            tasks: []
        };
        action.element = $(this).attr("ev:observer");
        if(action.element=='xforms-model'){
        	action.element= null;
        	target = model;
        }
        if(action.element=='xforms'){
        	action.element = null; 
    		target = xforms;
        }
        action.model = model;
        if(action.element!=null){
            $(action.element).live(action.event, function(event){
                var element = this;
                setTimeout(function(){
                    executeAction(element, action);
                }, 0);
            });
        }else{
            $(target).bind(action.event, function(event){
                var element = this;
                setTimeout(function(){
                    executeAction(element, action);
                }, 0);
            });
        }
        if (this.localName=="action"){
            $(this).children().each(function(i,childaction){
                bindTasks(i,childaction, action);
            });
        } else {
        	bindTasks(0,this,action);        
        }
    });
}

function bindTasks(index, action, parentAction){
	if($(action).children().length > 0){
		var newAction = {
            classname: "action",
            event: parentAction.event,
            expression: $(action).attr("if"),
            tasks: [],
            element: parentAction.element,
            model: parentAction.model
	    };
		$(action).children().each(function(i,val){
	        bindTasks(i,val,newAction);
	    });
		var task = createTask(newAction);
	    task.action = newAction;
	    parentAction.tasks.push(task);
	}else{
		var task = createTask(action);
	    task.action = parentAction;
	    parentAction.tasks.push(task);
	}
}

function createTask(el){
	if(el.classname == "action"){
		var task = {
	    classname: "task",
	    type: "action",   
        expression: el.expression
	    };
	}else{
		var type = el.localName;
	    var task = {
	        classname: "task",
	        type: type,
	        model: $(el).attr("model"),
	        submission: $(el).attr("submission"),
	        context: $(el).attr("context"),
	        ref: $(el).attr("ref"),
	        bind: $(el).attr("bind"),
	        at: $(el).attr("at"),
	        origin: $(el).attr("origin"),
	        nodeset: $(el).attr("nodeset"),
	        position: $(el).attr("position"),
	        value: $(el).attr("value"),
	        valueType: $(el).attr("valueType"),
	        text: $(el).text(),
	        resource: $(el).attr("resource"),
	        show: $(el).attr("show"),
	        expression: $(el).attr("if"),
            calculate: $(el).attr("calculate"),
	        target: $(el).attr("target"),
	        event: $(el).attr("ev:event"),
	        delay: $(el).attr("delay"),
            id: $(el).attr("id"),
	        name: $(el).attr("name"),
	        mask: $(el).attr("mask"),
	        title: $(el).attr("title"),
	        titleRef: $(el).attr("title-ref"),
	        uri: $(el).attr("uri"),
	        uriRef: $(el).attr("uri-ref"),
	        index: $(el).attr("index"),
	        backUri: $(el).attr("back-uri")
	    };
	}    
    return task;
}

function executeAction(element, action){
    var context = $(element).data("context");
    if (context!=null){
        xforms.indexes[context.repeatKey] = context.index;
    }
    var expression = replaceVariables(action.expression,action.model.variables);
    if (!seperateIfExpression(expression, context, action.model)) return;
    $(action.tasks).each(function(index,task){
        if (task.delay > 0){
            setTimeout(function(){
                evaluateAction(task,element,context,action);
            },task.delay )
        } else {
            evaluateAction(task,element,context,action);
        }
    });
}

function evaluateAction(task,element,context,action){
    var model = xforms.models[task.model] || action.model;
    var expression = replaceVariables(task.expression,action.model.variables);
    if (!seperateIfExpression(expression, context, model)) return;
    
    switch(task.type)
    {
	    case "action":
	    	$(task.action.tasks).each(function(index,nestedTask){
                if (nestedTask.delay > 0){
                    setTimeout(function(){
                        evaluateAction(nestedTask,element,context,action);
                    },nestedTask.delay )
                } else {
                    evaluateAction(nestedTask,element,context,action);
                }
	        });
		    break;
	    case "send":
	    	sendAction(element, task, model);
		    break;
	    case "insert":
	    	insertAction(element, task, model);
		    break;
	    case "delete":
	    	deleteAction(element, task, model);
	    	break;
	    case "setvalue":
	    	setValueAction(element, task, model);
	    	break;
	    case "dispatch":
	    	dispatchAction(element, task, model);
	    	break;
	    case "validate":
	    	validateAction(element, task, model);
	    	break;
	    case "resetValidation":
	    	resetValidation(element, task, model);
	    	break;
        case "variable":
        case "bind":
            variableAction(element, task, model);
            break;
	    case "message":
	    	alertAction(element, task, model);
	    	break;
	    case "confirm":
	    	confirmAction(element, task, model);
	    	break;
	    case "load":
	    	loadAction(element, task, model);
	    	break;
	    case "dynamicSubform":
	    	dynamicSubformAction(element, task, model);
	    	break;
    }
}

function seperateIfExpression(expression, context, targetModel){
	if(expression == null) return true;
	var statement = "";
	var subexpression = "";
	if(expression.indexOf('&&')!=-1 || expression.indexOf('||')!=-1){
		while(expression.indexOf('&&')!=-1 || expression.indexOf('||')!=-1){
			if(expression.indexOf('&&')!=-1){
				if(expression.indexOf('&&') < expression.indexOf('||')){
					subexpression = expression.substr(0,expression.indexOf('&&'));
			    	expression = expression.substr(expression.indexOf('&&'));
			    	statement = statement + evaluateIfExpression(subexpression, context, targetModel);
			    	statement = statement + expression.substr(0,2);
			    	expression = expression.substr(2);
				}else if(expression.indexOf('||')==-1){
					subexpression = expression.substr(0,expression.indexOf('&&'));
			    	expression = expression.substr(expression.indexOf('&&'));
			    	statement = statement + evaluateIfExpression(subexpression, context, targetModel);
			    	statement = statement + expression.substr(0,2);
			    	expression = expression.substr(2);
				}
			}else if(expression.indexOf('||')!=-1){
				if(expression.indexOf('||') < expression.indexOf('&&')){
					subexpression = expression.substr(0,expression.indexOf('||'));
			    	expression = expression.substr(expression.indexOf('||'));
			    	statement = statement + evaluateIfExpression(subexpression, context, targetModel);
			    	statement = statement + expression.substr(0,2);
			    	expression = expression.substr(2);
				}else if(expression.indexOf('&&')==-1){
					subexpression = expression.substr(0,expression.indexOf('||'));
			    	expression = expression.substr(expression.indexOf('||'));
			    	statement = statement + evaluateIfExpression(subexpression, context, targetModel);
			    	statement = statement + expression.substr(0,2);
			    	expression = expression.substr(2);
				}
		    }
		}
		statement = statement + evaluateIfExpression(expression, context, targetModel);
        return eval(statement);
	}else{
    	return evaluateIfExpression(expression, context, targetModel);
    }

}

function evaluateIfExpression(expression, context, targetModel){
    if(expression == null) return true;
    var re = new RegExp(/^(.+?)(==|<=|>=|!=|!<<<|!<<|!>>>|!>>|>>>|>>|<<<|<<)(.+)$/gi);
    var tokens = re.exec(expression);
    if (tokens != null) {
        var left = $.trim(tokens[1]);
        var operation = $.trim(tokens[2]);
        var right = $.trim(tokens[3]);
        var literalExp = new RegExp(/^['"](.*)['"]$/gi);
        var statement = "";
        var parts;
        // evaluate as xml
        if(operation=="!<<<"||operation=="!>>>"||operation==">>>"||operation=="<<<"){
            parts = literalExp.exec(left);
            if (parts == null) {
            	left = evaluateIfExpressionNode(left, context, targetModel);
            }
            literalExp = new RegExp(/^['"](.*)['"]$/gi);
            parts = literalExp.exec(right);        
            if (parts == null) {
            	right = evaluateIfExpressionNode(right, context, targetModel);
            }
            switch (operation){
            case ">>>":
            	statement = $(left).is($(right));
            	break;
            case "<<<":
            	statement = $(right).is($(left));
            	break;
            case "!>>>":
            	statement = !($(left).is($(right)));
            	break;
            case "!<<<":
            	statement = !($(right).is($(left)));
            	break;
            default:
            	//should never reach this
            	break;
            }
        // evaluate as strings
        }else{
            parts = literalExp.exec(left);
            if (parts == null) {
            	left = evaluateIfExpressionPart(left, context, targetModel);
            }
            literalExp = new RegExp(/^['"](.*)['"]$/gi);
            parts = literalExp.exec(right);        
            if (parts == null) {
            	right = evaluateIfExpressionPart(right, context, targetModel);
            }
            switch (operation){
            case ">>":
            	statement = "(" + right + ".indexOf(" + left + ")!=-1)";
            	break;
            case "<<":
            	statement = "(" + left + ".indexOf(" + right + ")!=-1)";
            	break;
            case "!>>":
            	statement = "(" + right + ".indexOf(" + left + ")==-1)";
            	break;
            case "!<<":
            	statement = "(" + left + ".indexOf(" + right + ")==-1)";
            	break;
            default:
            	statement = "(" + left + operation + right + ")";        
            }
        }
        return eval(statement);
    } else {
//        var value;
        var value = evaluateIfExpressionPart(value, context, targetModel);
//        if (expression.indexOf("instance(")==0 || context == null){
//            value = targetModel.find(expression).xmlText();
//        } else {
//            value = $(context.ref).xpath(expression).xmlText();
//        }
        return (value.length > 0);
    }
}

function evaluateIfExpressionPart(part, context, targetModel){
    if (part.indexOf("instance(")==0 || context == null){
    	part = targetModel.find(part).xmlText() || "";
    } else {
    	part = $(context.ref).xpath(part).xmlText();
    }
    return "'" + part + "'";
}

function evaluateIfExpressionNode(part, context, targetModel){
    if (part.indexOf("instance(")==0 || context == null){
    	part = targetModel.find(part);
    } else {
    	part = $(context.ref).xpath(part);
    }
    return part;
}

function variableAction(element, task, targetModel){
    var action = task.action;
    var model = action.model;
    var value = replaceVariables(task.text, model.variables);
    var position = 1;
    if(task.value!=null){
        var valuePath = replaceVariables(task.value, model.variables);
        var context = $(element).data("context");
        var boundNode;
        if (context!=null) boundNode = context.ref;
        if(boundNode!=null){
        	if(task.valueType != "node"){
        		value = $(boundNode).xpath(valuePath).xmlText();
                position = $($(boundNode).xpath(valuePath)).index();
        	}else{
        		value = "$(boundNode).xpath(valuePath)";
        		position = $($(boundNode).xpath(valuePath)).index();
        	}            
        } else {
        	if(task.valueType != "node"){
	            value = $(targetModel).xpath(valuePath).xmlText();
	            position = $($(targetModel).xpath(valuePath)).index();
        	}else{
        		value = "$(targetModel).xpath(valuePath)";
	            position = $($(targetModel).xpath(valuePath)).index();
        	}
        }
    }
    var name = task.name || task.id;
    if(name!=null) {
        if (task.calculate!=null) {
        	if(task.valueType != "node"){
        		var expression = "var value='" + value + "';"
            	+ " var position=" + position + ";" + task.calculate;
        	}else{
        		var expression = "var value=eval(value); var position=" + position + ";" + task.calculate;
        	}            
            for (varName in model.variables) {
                var fragment = "var " + varName + "='" + model.variables[varName] + "';";
                expression = fragment + expression;
            }            
            value = eval(expression);
        }
        model.variables["$" + name] = value;
    }
}
function replaceVariables(str, variables){
    if (str==null) return;
    var result = str;
    for (key in variables){
        result = result.replace(key,variables[key]);
    }
    for (key in xforms.variables){
        result = result.replace(key,xforms.variables[key]);
    }
    return result;
}
function loadAction(element, task, model){
	var linkUrl=null;
	if(task.ref){
        var ref = replaceVariables(task.ref, task.action.model.variables);
        var context = $(element).data("context");
        var boundNode;
        if (context!=null) boundNode = context.ref;
        if(boundNode!=null){
            linkUrl =  $(boundNode).xpath(ref).xmlText();
        } else {
            linkUrl =  $(model).xpath(ref).xmlText();
        }
	}
	else if(task.resource){
		linkUrl = replaceVariables(task.resource, task.action.model.variables);
	}
	if(task.show==="new" && linkUrl){
		window.open(linkUrl);
	}else if(task.show==="popup" && linkUrl){
		$.mobile.changePage(linkUrl,{role:"dialog"});
	}else if(linkUrl){
		window.location.href = linkUrl;
	}
}
function sendAction(element, task, model){
    var submission = model.submissions[task.submission];
    $(submission).trigger("xforms-submit");
}
function dispatchAction(element, task, model){
    var target = task.target;
    var event = task.event;
    // for custom events they can be added directly to the elements but disable supresses events so has to be done like below
    switch (event) {
        case "enable":
            $(target).each(function(){
                var el = this;
                el.disabled = false;
                if($(el).hasClass('xformSuggest-bit-editable-input')){
                    $(el).parent().parent().removeClass('ui-disabled');
                }else{
                    $(el).removeClass('ui-disabled');
                }
            });
            break;
        case "disable":
            $(target).each(function(){
                var el = this;
                el.disabled = true;
                if($(el).hasClass('xformSuggest-bit-editable-input')){
                    $(el).parent().parent().addClass('ui-disabled');
                }else{
                    $(el).addClass('ui-disabled');
                }
            });
            break;
        case "mask":
        	$(target).mask();
        	break;
        case "unmask":
        	$(target).unmask();
        	break;
        case "show":
        	$(target).show();
        	break;
        case "hide":
        	$(target).hide();
        	break;
        default:
            setTimeout(function(){
                $(target).trigger(event);
            },0 )
    }
}
function validateAction(element, task, model){
    var target = task.target;
    var name = task.name;
    var valid = true;
    
    $(target).each(function(){
    	var element = this;
        $(element).validate();
        valid = valid && $(element).valid();
    	 });
    if(!valid){
    	if($.mobile.sdCurrentDialog){
    		$.mobile.sdCurrentDialog.options.animate = false;
	    	$.mobile.sdCurrentDialog.close();
	    }
    	$('<div>').simpledialog2({
    	    mode: 'blank',
    		themeHeader: THEME,
    		themeDialog: THEME,
    	    headerText: '',
    	    headerClose: false,
    	    width: '33%',
    	    safeNuke:true,
    	    blankContent : '<div style="padding:10px;">Fields with the following symbol<span style="padding: 0 10px 0 0;"><span class="error ui-icon ui-icon-alert ui-icon-shadow"></span></span>contain errors or missing data. Please review your entry and try again.<div>' + 
    	    			   '<a rel="close" data-role="button" href="#" >OK</a>'
    	})
    }
    xforms.variables["$" + name] = "" + valid;
}


function resetValidation(element, task, model){
    var target = task.target;    
    $(target).each(function(){
    	var el = this;
    	var validator = $(el).validate();
    	validator.resetForm();
    });
}

function insertAction(element, task, targetModel){
    var action = task.action;
    var instance;
    var origin;
    var context = $(element).data("context");
    var boundNode;
    if (context!=null) boundNode = context.ref;
    var originPath = replaceVariables(task.origin, task.action.model.variables);
    if(boundNode!=null){
        origin = $(boundNode).xpath(originPath);
    } else {
        origin = action.model.find(originPath);
    }
    if (task.context!=null){
        var contextPath = replaceVariables(task.context, task.action.model.variables);
        context = targetModel.find(contextPath);
        instance = targetModel.getInstance(contextPath);
    } else {
        context = targetModel;
        instance = targetModel.defaultInstance;
    }
    if (task.nodeset!=null) {
        var nodesetPath = replaceVariables(task.nodeset, task.action.model.variables);
        context = $(context).xpath(nodesetPath);
    }

    var position = (task.position!=null) ? task.position : "after";
    if (origin != null) {
        var originClone = $(origin).clone();
        if(task.nodeset!=null && task.at!=null){
            var at = replaceVariables(task.at, task.action.model.variables);
            //look for index function to set selector to :eq(index)
            var re = new RegExp(/index\(['"](.*)['"]\)/gi);
            var parts = re.exec(task.at);
            if (parts != null) {
                var repeatKey = parts[1];
                var index = xforms.indexes[repeatKey] -1;
                at = ":eq(" + index + ")";
            }
            var node = null;
            if(context.length == 0){
            	node = context.prevObject;
            	$(node).append(originClone);
            }else{
            	node = $(context).filter(at);
                if (position=="before"){
                    $(node).before(originClone);
                } else {
                    $(node).after(originClone);
                }
            }
        } else {
        	if ($.browser.msie) {  
        		for(var count=0; count < originClone.length; count++){
        			context[0].appendChild(originClone[count]);	
        		}
        	}else{
        		$(context).append(originClone);
    		}
        }
        var event = jQuery.Event("xforms-insert");
        event.origin = task.origin;
        event.nodeset = task.nodeset;
        event.context = task.context;
        $(instance).trigger(event);
    }
}
function deleteAction(element, task, model){
    var action = task.action;
    var context = $(element).data("context");
    var boundNode;
    if (context!=null) boundNode = context.ref;
    if(boundNode!=null){
        if (task.context!=null){
            var contextPath = replaceVariables(task.context, task.action.model.variables);
            context = model.find(contextPath);
        } else {
            context = boundNode;
        }
    } else {
        var contextPath = replaceVariables(task.context, task.action.model.variables);
        context = model.find(contextPath);
    }
    if (task.nodeset!=null) {
        var nodesetPath = replaceVariables(task.nodeset, task.action.model.variables);
        context = $(context).xpath(nodesetPath);
    }
    if(task.nodeset!=null && task.at!=null){
    	var at = replaceVariables(task.at, task.action.model.variables);
        //look for index function to set selector to :eq(index)
        var re = new RegExp(/index\(['"](.*)['"]\)/gi);
        var parts = re.exec(task.at);
        if (parts != null) {
            var repeatKey = parts[1];
            var index = xforms.indexes[repeatKey]-1;
            at = ":eq(" + index + ")";
        }
        if ($.browser.msie) {  
        	/*try{*/
        	if($(context).filter(at).length != 0){
        		$(context).filter(at)[0].parentNode.removeChild($(context).filter(at)[0]);
        	}
        	/*}catch(e){
        		console.log("cant delete because " + e.message);
        	}*/   		
    	}else{
    		$(context).filter(at).remove();
		}
    } else {
        $(context).filter(":first").remove();
    }
    var instance = model.getInstance(task.context);
    var event = jQuery.Event("xforms-delete");
    $(instance).trigger(event);
}
function alertAction(element, task, model){
    var text = replaceVariables(task.text, task.action.model.variables);
    if($.mobile.sdCurrentDialog){
		$.mobile.sdCurrentDialog.options.animate = false;
    	$.mobile.sdCurrentDialog.close();
    }
    $('<div>').simpledialog2({
	    mode: 'button',
	    headerText: '',
	    headerClose: false,
	    buttonPrompt:  text,
	    themeDialog: 'd',
	    themeHeader: 'd',
	    themeInput: 'd',
	    themeButtonDefault: 'd',
	    width: '33%',
	    buttons : {
	      'OK': {
	        click: function () { 
	          $('#buttonoutput').text('OK');
	        }
	      }
	    }
	  })
}
function confirmAction(element,task,model){
    var text = replaceVariables(task.text, task.action.model.variables);
	$('<div>').simpledialog2({
	    mode: 'button',
	    headerText: 'Confirm',
	    headerClose: false,
	    buttonPrompt: text,
	    themeDialog: 'd',
	    themeHeader: 'd',
	    themeInput: 'd',
	    themeButtonDefault: 'd',
	    buttons : {
	      'OK': {
	        click: function () { 
	          $('#buttonoutput').text('OK');
	          var event = jQuery.Event("confirm-ok");
	          $(element).trigger(event);
	        }
	      },
	      'Cancel': {
	        click: function () { 
	          $('#buttonoutput').text('Cancel');
	          var event = jQuery.Event("confirm-cancel");
	          $(element).trigger(event);
	        },
	        icon: "delete"
	      }
	    }
	  })
}
function setValueAction(element, task, targetModel){
    var action = task.action;
    var value = replaceVariables(task.text, task.action.model.variables);
    if(task.value!=null){
        var valuePath = replaceVariables(task.value, task.action.model.variables);
        var context = $(element).data("context");
        var boundNode;
        if (context!=null) boundNode = context.ref;
        if(boundNode!=null){
            value = $(boundNode).xpath(valuePath).xmlText();
        } else {
            value = $(action.model).xpath(valuePath).xmlText();
        }
    }
    var refPath = replaceVariables(task.ref, task.action.model.variables);
    var ref = targetModel.setValue(refPath, value);
}
function dynamicSubformAction(element,task,model){
	var targetEl = $.find(task.mask);
	var targetModel = xforms.findModel("__dynamicSubformModel");
	// mask form
	dispatchAction(element,{
			target: targetEl,
			event: "mask"
		},targetModel);
	//set title
	if(task.titleRef){
        var titleValuePath = replaceVariables(task.titleRef, task.action.model.variables);
        var titleContext = $(element).data("context");
        var titleBoundNode, titleValue;
        if (titleContext!=null) titleBoundNode = titleContext.ref;
        if(titleBoundNode!=null){
        	titleValue = $(titleBoundNode).xpath(titleValuePath).xmlText();
        }
	    targetModel.setValue("instance('__dynamicSubformHeader')/data/title", titleValue);
	}else{
		targetModel.setValue("instance('__dynamicSubformHeader')/data/title", task.title);
	}
	//set uri
	if(task.uriRef){
        var uriValuePath = replaceVariables(task.uriRef, task.action.model.variables);
        var uriContext = $(element).data("context");
        var uriBoundNode, uriValue;
        if (uriContext!=null) uriBoundNode = uriContext.ref;
        if(uriBoundNode!=null){
        	uriValue = $(uriBoundNode).xpath(uriValuePath).xmlText();
        }
	    targetModel.setValue("instance('__dynamicSubformUri')/data/uri", uriValue);
	}else{
		targetModel.setValue("instance('__dynamicSubformUri')/data/uri", task.uri);
	}
	//send submission
    var submission = targetModel.submissions["get-dynamic-subform"];
    $(submission).trigger("xforms-submit");
	//load subform
	window.location.href = "#__dynamicSubformView";
	//unmask form
	dispatchAction(element,{
			target: targetEl,
			event: "unmask"
		},targetModel);
    $("#__dynamicSubformBackBtn").unbind("click", function(event){
    	var backUri = task.backUri || "#main";
    	window.location.href = backUri;
    });
    $("#__dynamicSubformBackBtn").bind("click", function(event){
    	var backUri = task.backUri || "#main";
    	window.location.href = backUri;
    });
}

function onSubmit(submission, event){
    if (event!=null){
        event.preventDefault();
        event.stopPropagation();
    }
    var method = submission.method.toUpperCase();
    $.mobile.loadingMessage = 'Processing';
    $.mobile.showPageLoadingMsg();
    var model = submission.model;
    var xml = null;
    var data = null;
    if (submission.ref!=null){
        data = model.find(submission.ref);
    }
    var url = null;
    if(submission.action == undefined && submission.actionRef != undefined){
    		url = $(model).xpath(submission.actionRef).xmlText();
    		var test = null;
    }else{
    	url = submission.action;
    }
    if(method=="POST" || method=="PUT"){
    	if(data!==null){
        	xml = $(data).serializeXML();
    	}
        $.ajax({
        	headers: {
        		XThemisProcess: xforms.processId,
        		XThemisTask: xforms.taskId,
        		XThemisForm: location.href
    		},
            contentType: 'application/xml',
            context: submission,
            data: xml,
            dataType: 'xml',
            async: submission.async,
            processData: false,
            success: onSubmitSuccess,
            error: function(jqXHR, textStatus, errorThrown) {
            	$.mobile.hidePageLoadingMsg();
                $("body").unmask();
                var event = jQuery.Event("xforms-submit-error");
                event.submission = submission;
                event.textStatus = textStatus;
                event.errorThrown = errorThrown;
                $(submission).trigger(event);
                alert(textStatus);
            },
            timeout: 60*1000,
            type: method,
            url: url
        });
    } else if (method=="GET") {
    	var queryString = "";
    	if(data!==null){
    		queryString = domToQuery(data);
    		if(submission.queryString != null){
    			queryString += submission.queryString.replace('?','&');
    		}
    	}else if(submission.queryString != null){
    		queryString = submission.queryString;
    	}
        $.ajax({
        	headers: {
	    		XThemisProcess: xforms.processId,
	    		XThemisTask: xforms.taskId,
	    		XThemisForm: location.href
			},
            context: submission,
            dataType: 'xml',
            async: submission.async,
            processData: false,
            success: onSubmitSuccess,
            error: function(jqXHR, textStatus, errorThrown) {
                $("body").unmask();
            	$.mobile.hidePageLoadingMsg();
                var event = jQuery.Event("xforms-submit-error");
                event.submission = submission;
                event.textStatus = textStatus;
                event.errorThrown = errorThrown;
                $(submission).trigger(event);
            },
            timeout: 60*1000,
            type: "GET",
            url: url + queryString
        });
    }
}
function onSubmitSuccess(data, textStatus, jqXHR) {
	$.mobile.hidePageLoadingMsg();
	var submission = this;
    var model = submission.model;
    var rootPage;
	if ( submission.replace == 'all' ) {
        if ($("#loading").length==0) $("body").append('<div id="loading" data-role="page">Loading...</div>');
        $.mobile.changePage($("#loading"));
        setTimeout(function(){
            xforms.clear();
            $(data).find("[data-role='model']").each(function(){
                var script = this;
                var html = $(script).serializeXML();
                $("body").append(html);
            });
            $(data).find("[data-role='page']").each(function(){
                var page = this;
                rootPage = rootPage || page.id;
                var html = $(page).serializeXML();
                $("body").append(html);
            });
            loadXForms(document);
            $.mobile.changePage($("#" + rootPage));
            repaintElement("#" + rootPage);
        },700);
	} else if(submission.instance){
        var instance = model.instances[submission.instance];
        if($.browser.msie){
        	instance.content = $(data.firstChild);
        }else{
        	instance.content = $(data);	
        }        
        var event = jQuery.Event("xforms-refresh");
        $(instance).trigger(event);
    }
    var event = jQuery.Event("xforms-submit-done");
    event.submission = submission;
    $(submission).trigger(event);
}
function domToQuery(node){
	var queryString = "";
	var rids = $(node).children("[restIndex]");
	rids.sort(function(a,b){
		return (parseInt($(a).attr('restIndex')) - parseInt($(b).attr('restIndex')));
	});
	rids.each(function(index){
		queryString += "/" + this.textContent;
	});
	var params = $(node).children(":not([restIndex])");
	params.each(function(index){
		if(index===0){
			queryString += "?";
		}
		var encode = this.attributes["encode"];
		var content = encode!=null ? encodeURIComponent(this.textContent) : this.textContent;
		queryString += this.tagName + "=" + content;
		if(index != params.length-1){
			queryString += "&";
		}
	});
	return queryString;
}
function cacheKiller(url){
	var ck = new Date().getTime();
	if(url.indexOf("?")!=-1){
		url += '&_dc=' + ck;
	}else{
		url += '?_dc=' + ck;
	}
	return url;
}
// resize textareas on bind of data so that they are sized properly
function autoTextAreaSize(ele) {  
    ele.style.height = 'auto';  
    var newHeight = (ele.clientHeight < ele.scrollHeight ? ele.scrollHeight + 15 : ele.clientHeight);  
    ele.style.height = newHeight.toString() + 'px';  
 }  
